import time
import socket
from cStringIO import StringIO
from hashlib import md5
from twisted.internet import reactor, threads
from twisted.enterprise import adbapi       
from twisted.python.util import println
import random
############################HELPER METHODS ##########################
def xor_blocks(xdata, ydata):
    '''
    given data blocks in xdata and ydata, xor them and return a string.
    '''
    buff = StringIO()
    for xc,yc in zip(xdata, ydata):
        buff.write(chr(ord(xc)^ord(yc)))
    return buff.getvalue()
def get_file_id(path):
        f = open(path)
        fh = md5()
        while True:
            s = f.read(1<<25)
            if not s:
                break
            fh.update(s)
        return fh.hexdigest()

def set_public_key(rpc_client):
    if not rpc_client.status:
        reactor.callLater(3, set_public_key, rpc_client)
    else:
        d = rpc_client.get_public_key()
        d.addCallback(rpc_client.enable_encryption)
        d.addErrback(errorHandler("Can not enable the encryption for the rpc_client"))
          
def get_free_port():
        s = socket.socket()
        s.bind(('',0))
        port = s.getsockname()[1]
        s.close()
        return port
      
def get_zero_hash(length):
        """Return the hash value for a block of zeros, block's length is len"""
        return md5('\x00'*length).hexdigest()

def choose_peers_for_download(me, bid2peers):
        print "choose_peers_for_download"
        aux = {}        
        for bid,peers in bid2peers.iteritems():                        
            if me in peers:
                #in order to avoid downloading choose yourself.
                aux[bid] = me
            else:
                if not peers:
                    print "for bid = ", bid, " there is no peer that has the block"
                    return None
                #randomly choose a peer to download this block
                aux[bid] = random.choice(peers)
        ret = {}
        for bid,peer in aux.iteritems():
            if peer not in ret:
                #using a list here is important b/c of serialization
                ret[peer] = []
            ret[peer].append(bid)        
        return ret
def errorHandler(msg):
    def nit(failure):
        print str(failure)
        raise Exception(msg)
    return nit